/*
 * Copyright (C) 2013 Daniel Treffenstädt <daniel@treffenstaedt.de>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
 * 02110-1301  USA
 */

#include "OObject.h"
#include "OString.h"
#include "OThreadLoop.h"

O_START_NAMESPACE

std::unordered_set<Object*>			Object::m_objects;

Object::Object() :
	m_thread(0)
{
	m_parent		= 0;
	m_objects.insert(this);
}

Object::Object(Object *parent) :
	m_thread(0)
{
	m_parent		= parent;
	m_objects.insert(this);
}

Object::~Object()
{
	if (m_parent != 0)
	{
		m_parent->removeChild(this);
	}

	for (int i = 0; i < m_children.length(); i++)
	{
		m_children[i]->m_parent	= 0;
		delete m_children[i];
	}

	m_children.clear();
}

void Object::moveToThread(ThreadLoop *t)
{
	if (m_thread != 0)
	{
		m_thread->unload(this);
		m_thread	= 0;
	}

	m_objects.erase(this);

	if (t == 0)
	{
		m_objects.insert(this);
	}
	else
	{
		m_thread	= t;
		m_thread->load(this);
	}
}

Object* Object::parent()
{
	return m_parent;
}

bool Object::hasParent()
{
	return m_parent != 0;
}

void Object::setParent(Object* o)
{
	m_parent	= o;
	m_parent->addChild(this);
}

void Object::removeParent()
{
	m_parent	= 0;
	m_parent->removeChild(this);
}

bool Object::addChild(Object* o)
{
	if (m_children.contains(o))
	{
		return false;
	}
	m_children.append(o);
	if (o->m_parent != this)
	{
		o->setParent(this);
	}
	return true;
}

bool Object::hasChild(Object* o)
{
	return m_children.contains(o);
}

Object* Object::getChild(int index)
{
	if (m_children.length() > index)
	{
		return m_children[index];
	}
	return 0;
}

bool Object::removeChild(int index)
{
	if (m_children.length() > index)
	{
		m_children.removeAt(index);
		return true;
	}
	return false;
}

bool Object::removeChild(Object* o)
{
	if (!m_children.contains(0))
	{
		return false;
	}
	m_children.removeOne(o);
	return true;
}

int Object::children()
{
	return m_children.length();
}

Object* Object::operator[] (int index)
{
	if (m_children.length() > index)
	{
		return m_children[index];
	}
	return 0;
}

void Object::callEventsS()
{
	for (std::unordered_set<Object*>::iterator it = m_objects.begin(); it != m_objects.end(); it++)
	{
		(*it)->callEventsD();
	}
}

void Object::callEventsD()
{
	m_callbacks.front()();
	m_callbacks.pop();
}

O_END_NAMESPACE
